package com.nitobi.harvest.service
{
	import com.hurlant.util.Base64;
	import com.nitobi.harvest.model.HarvestModel;
	import com.nitobi.harvest.vo.DayEntryVO;
	import com.nitobi.harvest.vo.ProjectVO;
	import com.nitobi.harvest.vo.TaskVO;
	import com.nitobi.util.Constants;
	import com.nitobi.util.Encryption;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.xml.XMLNode;
	
	import mx.collections.ArrayCollection;
	import mx.rpc.AbstractService;
	import mx.utils.StringUtil;
	
	public class HarvestService extends AbstractService
	{
		
		private static var instance:HarvestService;
		
		private var _url:String;
		private var _user:String;
		private var _pass:String;
		private var _companyName:String;
		private var _headers:Array = [];
		
		private var model:HarvestModel;
		
		public function HarvestService():void
		{
			if( HarvestService.instance != null ) 
			{
				throw new Error( "HarvestService is a singleton." );
			}		
		}

		public static function getInstance():HarvestService
		{
			if( HarvestService.instance == null ) 
			{
				HarvestService.instance = new HarvestService();
			}
			return HarvestService.instance;
		}	
				
		public function init():void
		{
			model = HarvestModel.getInstance();
			
			_user = Encryption.readEncryptedStringSetting("harvestUser");
			_pass = Encryption.readEncryptedStringSetting("harvestPass");	
			_companyName = Encryption.readEncryptedStringSetting("companyName");
			_url = Constants.HTTPS + _companyName + Constants.HARVEST_DOMAIN;
			
			var userData:String = Base64.encode(_user + ":" + _pass);
			var authorize:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + userData);
			var accept:URLRequestHeader = new URLRequestHeader("Accept", "application/xml");
			_headers.push(authorize);
			_headers.push(accept);		
			
			getHarvestDataDaily(populateLists, harvestError);	
		}
		
		public function getHarvestDataDaily(callback:Function, fail:Function):void
		{
			trace("getHarvestDataDaily");
			
			var request:URLRequest = new URLRequest(_url + "/daily");
			request.contentType = "application/xml";
			request.requestHeaders = _headers;
			request.data = "";
			request.method = URLRequestMethod.GET;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, fail);
			loader.load(request);			
		}
		
		public function populateLists(e:Event):void
		{
			trace("populateLists");
			
			var xml:XML = new XML(e.target.data);
			populateProjectList(xml);
			populateDailyEntries(xml);

		}
		
		public function populateDailyEntries(xml:XML):void
		{
			trace("populateDailyEntries");

			var dayEntriesAC:ArrayCollection = new ArrayCollection();
			var dayEntriesList:XMLList = new XMLList(xml.day_entries.children());
			var dailyHours:Number = 0;
			
			for each (var dayEntry:XML in dayEntriesList)
			{
				var dayEntryVO:DayEntryVO = new DayEntryVO();
				dayEntryVO._id = dayEntry.id;
				dayEntryVO._spentAt = dayEntry.spent_at;
				dayEntryVO._userId = dayEntry.user_id;
				dayEntryVO._client = dayEntry.client;
				dayEntryVO._projectId = dayEntry.project_id;
				dayEntryVO._project = dayEntry.project;
				dayEntryVO._taskId = dayEntry.task_id;
				dayEntryVO._task = dayEntry.task;
				dayEntryVO._hours = dayEntry.hours;
				dayEntryVO._notes = dayEntry.notes;
				dayEntryVO._createdAt = dayEntry.created_at;
				// only returned if timer is running for the entry
				dayEntryVO._timerStartedAt = dayEntry.timer_started_at;
				if (dayEntryVO._timerStartedAt.length > 0)
					dayEntryVO._timerStartedAt = Constants.TIMER_RUNNING;
				else
					dayEntryVO._timerStartedAt = Constants.TIMER_STOPPED;	
				dayEntriesAC.addItem(dayEntryVO);
				dailyHours += dayEntryVO._hours;
			}
			model.dailyEntriesAC = dayEntriesAC;
			model.todaysHours = dailyHours;
		}
		
		public function populateProjectList(xml:XML):void
		{
			trace("populateProjectList");

			var projectAC:ArrayCollection = new ArrayCollection();
			var projectList:XMLList = new XMLList(xml.projects.children());
			
			for each (var project:XML in projectList)
			{
				var taskAC:ArrayCollection = new ArrayCollection();
				var projVO:ProjectVO = new ProjectVO();
				projVO._name = project.name;
				projVO._id = project.id;
				projVO._client = project.client;
				
				var taskList:XMLList = new XMLList(project.tasks.children());
				
				for each (var task:XML in taskList)
				{
					var taskVO:TaskVO = new TaskVO();
					taskVO._name = task.name;
					taskVO._id = task.id;
					taskVO._billable = task.billable;
					taskAC.addItem(taskVO);
				}
				
				projVO._taskList = taskAC;
				projectAC.addItem(projVO);
			}
			model.projectListAC = projectAC;		
		}
				
		public function toggleTimer(dayEntryId:int, callback:Function, fail:Function):void
		{
			trace("toggleTimer");
			
			var request:URLRequest = new URLRequest(_url + "/daily/timer/" + dayEntryId);
			request.contentType = "application/xml";
			request.requestHeaders = _headers;
			request.data = "";
			request.method = URLRequestMethod.GET;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, fail);
			loader.load(request);				
		}
		
		public function createHarvestEntry(notes:String, hours:String, projectId:String, taskId:String, callback:Function, fail:Function):void
		{
			trace("createHarvestEntry");
			
			var today:Date = new Date();
			
			var requestParams:XML = 				
				<request>
				  <notes>{notes}</notes>
				  <hours>{hours}</hours>
				  <project_id type="integer">{Number(projectId)}</project_id>
				  <task_id type="integer">{Number(taskId)}</task_id>
				  <spent_at type="date">{today}</spent_at>
				</request>;
			
			var request:URLRequest = new URLRequest(_url + "/daily/add");
			request.contentType = "application/xml";
			request.requestHeaders = _headers;
			request.data = requestParams;
			request.method = URLRequestMethod.POST;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, fail);
			loader.load(request);					
						
			/******** response from Harvest API
				<?xml version="1.0" encoding="UTF-8"?>
				<timer>
				  <!-- new entry -->
				  <day_entry>
				    <id type="integer">195168</id>
				    <client>Iridesco</client>
				    <project>Harvest</project>
				    <task>Backend Programming</task>
				    <hours>0.00</hours>
				    <notes>Test api support</notes>
				
				    <!-- OPTIONAL returned only if a timer was started -->
				    <timer_started_at type="datetime">
				      Wed, 17 Oct 2006 10:45:07 +0000
				    </timer_started_at>
				  </day_entry>
				
				  <!-- OPTIONAL returned only if a timer for another -->
				  <!--          day_entry was stopped as a result    -->
				  <hours_for_previously_running_timer type="float">
				    0.87
				  </hours_for_previously_running_timer>
				</timer>
			**/
		}
		
		public function updateHarvestEntry(projectId:String, taskId:String, hours:String, notes:String, dayEntryId:int, callback:Function, fail:Function):void
		{		
			trace("updateHarvestEntry");
			var requestParams:XML = 				
				<request>
				  <notes>{notes}</notes>
				  <hours type="float">{Number(hours)}</hours>
				  <project_id type="integer">{Number(projectId)}</project_id>
				  <task_id type="integer">{Number(taskId)}</task_id>
				</request>;

			var request:URLRequest = new URLRequest(_url + "/daily/update/" + dayEntryId);
			request.contentType = "application/xml";
			request.requestHeaders = _headers;
			request.data = requestParams;
			request.method = URLRequestMethod.POST;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, fail);
			loader.load(request);				
		}
		
		public function deleteHarvestEntry(dayEntryId:String, callback:Function, fail:Function):void
		{
			trace("deleteHarvestEntry");
			var request:URLRequest = new URLRequest(_url + "/daily/delete/" + dayEntryId);
			request.contentType = "application/xml";
			request.requestHeaders = _headers;
			request.data = "";
			request.method = URLRequestMethod.DELETE;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, fail);
			loader.load(request);				
		}
		
		public function harvestError(e:IOErrorEvent):void
		{
			trace("harvestError");
		}		
	}
}